// Copyright Leonid Shlyapnikov 2010
// Distributed under the GNU Lesser General Public License http://www.gnu.org/licenses/lgpl.html
//    author: Leonid Shlyapnikov, created on: Jan 30, 2010

#ifndef FIXPARSER_CPP_SRC_MAIN_FIXPARSER_FIELD_H_
#define FIXPARSER_CPP_SRC_MAIN_FIXPARSER_FIELD_H_

#include <boost/utility.hpp>
#include <string>

#include "./Base.h"
#include "./String.h"
#include "./util.h"

namespace fixparser {

class MemoryArea;
class FieldListIterator;

class Field: public Base {
public:
    friend class MemoryArea;
    friend class FieldListIterator;
    friend class FieldList;
    template<class T> friend class SimpleFixMessage;

    static const char SOH = 0x01;

    bool isEmpty() const { return (0 == this->value_.length()); }

    const String& tag() const { return this->tag_; }
    const String& value() const { return this->value_; }

    void setTag(const std::string& new_tag) { this->tag_.assign(new_tag); }
    void setValue(const std::string& new_value) { this->value_.assign(new_value); }

    void setTag(const String& new_tag) { this->tag_.assign(new_tag); }
    void setValue(const String& new_value) { this->value_.assign(new_value); }

    void setTag(const char* new_tag) { this->tag_.assign(new_tag); }
    void setValue(const char* new_value) { this->value_.assign(new_value); }

    template<typename T>
    T* writeTo(T* output) const {
        output->write(tag_.c_str(), tag_.length());
        output->put('=');
        output->write(value_.c_str(), value_.length());
        output->put(0x01);
        return output;
    }

    template<class VISITOR>
    void acceptVisitor(VISITOR* visitor) {
        visitor->visit(this);
    }

    template<class VISITOR>
    void acceptVisitor(VISITOR* visitor) const {
        visitor->visit(this);
    }

    template<class VISITOR>
    void acceptVisitor(const VISITOR* visitor) const {
        visitor->visit(this);
    }

    unsigned int calculateChecksum() const {
        unsigned int result = 0;

        result += fixparser::calculateChecksum(this->tag_);
        result += '=';
        result += fixparser::calculateChecksum(this->value_);
        result += 0x01; // SOH

        return result;
    }

    Field* next() const {
        return this->next_;
    }

private:
    explicit Field(MemoryArea* const memoryArea):
        memoryArea_(memoryArea), tag_(memoryArea), value_(memoryArea), next_(0) {
    }

    virtual ~Field() {
    }

    /** only FieldList can link fields, see friends declarations */
    void setNext(Field* next) {
        if (0 == next) {
            BOOST_THROW_EXCEPTION(std::invalid_argument("Argument next is NULL"));
        }
        this->next_ = next;
    }

    /** only FieldList can ulink fields, see friends declarations */
    void unlink() {
        this->next_ = 0;
    }

    MemoryArea* const memoryArea_;
    String tag_;
    String value_;
    Field* next_;
};

}

#endif  // FIXPARSER_CPP_SRC_MAIN_FIXPARSER_FIELD_H_
